/**
  ******************************************************************************
  * @file    bsp_usart_ex.c
  * @author  Iron
  * @date    2018-08-08
  * @version v1.0
  * @brief   bsp_usart_ex c file
  */

/** @addtogroup GROUP_BSP
  * @{
  */

/* includes ------------------------------------------------------------------*/
#include "bsp_usart_ex.h"

/* BEBUG LOG */
#include "debug_log.h"
#define LOG_LOCAL_LEVEL DBG_LOG_DEBUG
DBG_LOG_TAG("BSP_USART_EX");

/* private typedef -----------------------------------------------------------*/
/* private macro -------------------------------------------------------------*/
/* private variables ---------------------------------------------------------*/
/* private function prototypes -----------------------------------------------*/
/* private functions ---------------------------------------------------------*/

static void bsp_usart_rx_indicate_cb(void *handle, uint32_t length)
{
    bsp_usart_handle_t *husart = handle;
    if (husart && husart->evt_handle)
    {
        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
        xEventGroupSetBitsFromISR(husart->evt_handle, BSP_USART_RX_EVT, &xHigherPriorityTaskWoken);
        if (husart->rx_indicate) husart->rx_indicate(husart, length, &xHigherPriorityTaskWoken);
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
}

static void bsp_usart_tx_complete_cb(void *handle)
{
    bsp_usart_handle_t *husart = handle;
    if (husart && husart->evt_handle)
    {
        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
        xEventGroupSetBitsFromISR(husart->evt_handle, BSP_USART_TXC_EVT, &xHigherPriorityTaskWoken);
        if (husart->tx_complete) husart->tx_complete(husart, &xHigherPriorityTaskWoken);
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
}

int32_t bsp_usart_ex_init(bsp_usart_handle_t *husart, bsp_usart_id_t uart, uint32_t baudrate,
                          usart_ex_isr_rx_indicate_t rx_indicate, usart_ex_isr_tx_complete_t tx_complete)
{
    if (uart >= BSP_USART_MAX)
    {
        return -1;
    }
    husart->uart = uart;
    husart->rx_indicate = rx_indicate;
    husart->tx_complete = tx_complete;
    husart->evt_handle = xEventGroupCreateStatic(&husart->evt);
    if (husart->evt_handle == NULL)
    {
        DBG_LOGE(TAG, "uart %d event group create error.", uart);
        return -2;
    }

    return bsp_usart_init(husart, uart, baudrate, bsp_usart_rx_indicate_cb, bsp_usart_tx_complete_cb);
}

int32_t bsp_usart_send_ex(bsp_usart_handle_t *husart, uint8_t *data, int32_t len, uint32_t timeout)
{
    int32_t res;

    xEventGroupClearBits(husart->evt_handle, BSP_USART_TXC_EVT);

    res = bsp_usart_dma_tx(husart->uart, data, len);
    if (res == len)
    {
        EventBits_t bits = xEventGroupWaitBits(husart->evt_handle, BSP_USART_TXC_EVT, pdTRUE, pdTRUE, pdMS_TO_TICKS(timeout));
        if (bits & BSP_USART_TXC_EVT)
        {
            return len;
        }
    }

    DBG_LOGE(TAG, "usart %d send timeout.", husart->uart);
    return 0;
}

// The function caller take the responsibility to keep "data" safe!
int32_t bsp_usart_send_tx_no_wait(bsp_usart_handle_t *husart, uint8_t *data, int32_t len)
{
    return bsp_usart_dma_tx(husart->uart, data, len);
}

int32_t bsp_usart_getbyte_ex(bsp_usart_handle_t *husart, uint8_t *data, uint32_t timeout)
{
    int32_t res = 0;

    do
    {
        res = bsp_usart_rx(husart->uart, data, 1);
        if (res != 1)
        {
            EventBits_t bits = xEventGroupWaitBits(husart->evt_handle, BSP_USART_RX_EVT, pdTRUE, pdTRUE, pdMS_TO_TICKS(timeout));
            if (!(bits & BSP_USART_RX_EVT)) break;
        }
    }
    while (res != 1);

    return res;
}

int32_t bsp_usart_recv_ex(bsp_usart_handle_t *husart, uint8_t *data, int32_t size, uint32_t timeout)
{
    int32_t res, rxlen = 0;

    for (rxlen = 0; rxlen < size;)
    {
        res = bsp_usart_rx(husart->uart, &data[rxlen], (size - rxlen));
        if (res > 0)
        {
            rxlen += res;
        }
        else
        {
            EventBits_t bits = xEventGroupWaitBits(husart->evt_handle, BSP_USART_RX_EVT, pdTRUE, pdTRUE, pdMS_TO_TICKS(timeout));
            if (!(bits & BSP_USART_RX_EVT)) break;
        }
    }

    return rxlen;
}

int32_t bsp_usart_get_rx_buf_len_ex(bsp_usart_handle_t *husart)
{
    return bsp_usart_rx_buf_len(husart->uart);
}

/**
  * @}
  */

/******************* (C)COPYRIGHT 2018 ***** END OF FILE *********************/
